import {boundClass} from "autobind-decorator";
import axios from "axios";


export interface ISseEmitterHandler {

    eventSource: EventSource
    subscribeUrl: string

    create(): ISseEmitterHandler

    registerOpenListener(callback?): ISseEmitterHandler

    registerErrorListener(callback?): ISseEmitterHandler

    registerMessageListener(callback?): ISseEmitterHandler
}

// @boundClass
class SseEmitterHandler implements ISseEmitterHandler {

    subscribeUrl: string;
    unSubscribeUrl: string;
    eventSource: EventSource;
    retryCount: 3;
    topics: [] = [];

    constructor(subscribeUrl, unSubscribeUrl) {
        this.subscribeUrl = subscribeUrl
        this.unSubscribeUrl = unSubscribeUrl
    }

    static of(subscribeUrl, unSubscribeUrl): SseEmitterHandler {
        return new SseEmitterHandler(subscribeUrl, unSubscribeUrl)
    }

    retry(runnable) {
        if (!runnable) {
            throw new Error("重试函数异常")
        }
        try {
            runnable()
        } catch (e) {
            if (this.retryCount-- > 0) {
                this.retry(runnable)
            }
        }
    }

    fetchEventSource() {
        if (this.eventSource) {
            console.log('this.eventSource1', this.eventSource)
            return
        }
        try {

            const url = new URL(`${this.subscribeUrl}`, location.origin)


            // console.log('url', url,url.href)
            this.eventSource = new EventSource(url.href)

            // console.log('this.eventSource2', this.eventSource)
        } catch (e) {
            console.log(e)
        }

    }

    create() {
        if (this.eventSource) {
            console.log('this.eventSource 存在', this.eventSource)
            return this
        }
        this.retry(() => {
            // console.log('this',this)
            this.fetchEventSource()
        })
        return this
        // console.log('this.eventSource',this.eventSource)
    }

    addTopic(topic): SseEmitterHandler {
        // console.log('addTopic', topic)
        if (!this.topics.includes(topic)) {
            this.topics.push(topic)
        }

        return this;
    }

    removeTopic(topic): SseEmitterHandler {
        // console.log('removeTopic', topic)
        if (this.topics.includes(topic)) {
            const index = this.topics.indexOf(topic)
            this.topics.splice(index, 1)
        }

        return this;
    }

    async subscribe(topic) {
        console.log('subscribe', this.topics, topic, this.eventSource)
        // Promise.
        if (this.topics?.includes(topic)) {
            return
        }

        const result = await axios.get(this.subscribeUrl, {

            params: {topic: topic}
        })
        // console.log('subscribe', this.topics, this, result)
        this.addTopic(topic)
        // trackGps({deviceNo:topic}).catch(e=>e)
        // console.log('subscribe', this.topics)

    }

    async unSubscribe(topic) {
        // console.log('unSubscribe', this.topics, topic)

        if (this.topics.includes(topic)) {
            const result = await axios.get(  this.unSubscribeUrl,{

                params: {topic: topic}
            })
            // console.log('unSubscribe', result, this.topics)
            this.removeTopic(topic)
            // console.log('unSubscribe', this.topics)
        }
    }

    subscribeHandle(subscribe, callback?): SseEmitterHandler {
        this.eventSource.addEventListener(subscribe, (event) => {
            if (callback) {
                callback(event)
            } else {
                console.log(subscribe, 'event', event)
            }
        })
        return this
    }

    registerOpenListener(callback?): SseEmitterHandler {
        this.eventSource.onopen = (event) => {
            if (callback) {
                callback(event)
            } else {
                console.log('onopen event', event)
            }
        }
        return this
    }

    registerErrorListener(callback?): SseEmitterHandler {
        this.eventSource.onerror = (event) => {
            if (callback) {
                callback(event)
            } else {
                console.log('onerror event', event)
            }
        }
        return this
    }

    registerMessageListener(callback?): SseEmitterHandler {
        this.eventSource.onmessage = (event) => {
            if (callback) {
                callback(event)
            } else {
                console.log('onmessage event', event)
            }
        }
        return this
    }
}

export {SseEmitterHandler}

